﻿using System;
using System.Collections.Generic;
using Busconeitor.Domain.Entities;
using Busconeitor.Domain.Repositories;
using NHibernate;
using NHibernate.Criterion;

namespace Busconeitor.DataLayer
{
    public class NHibernateRepositoryBaseImpl<T> : IRepository<T> where T : BaseEntity
    {
        protected readonly ISessionFactory Factory;

        protected ISession CurrentSession
        {
            get { return Factory.GetCurrentSession(); }
        }

        public NHibernateRepositoryBaseImpl(ISessionFactory factory)
        {
            Factory = factory;
        }

        #region Implementation of IRepository<T>

        public T GetOne(object id)
        {
            return CurrentSession.Get<T>(id);
        }

        public long Count()
        {
            var criteria = CurrentSession.CreateCriteria<T>();
            criteria.SetProjection(Projections.RowCount());
            var countMayBeInt32OrInt64DependingOnDatabase = criteria.UniqueResult();

            return Convert.ToInt64(countMayBeInt32OrInt64DependingOnDatabase);
        }

        public void Add(T entity)
        {
            CurrentSession.Save(entity);
        }

        public void Update(T entity)
        {
            CurrentSession.Update(entity);
        }

        public void Delete(T entity)
        {
            if (!CurrentSession.Contains(entity))
                CurrentSession.Load(entity, entity.Id);

            CurrentSession.Delete(entity);
        }

        public IEnumerable<T> GetSlice(int slice, int quantity, string order, bool @ascending)
        {
            return CurrentSession.CreateCriteria<T>()
                    .SetFirstResult(slice * quantity)
                    .SetMaxResults(quantity)
                    .AddOrder(new Order(order, ascending))
                    .List<T>();
        }

        #endregion

        public virtual IEnumerable<T> GetAll(string orderByField, bool ascending)
        {
            return CurrentSession.CreateCriteria<T>()
                .AddOrder(new Order(orderByField, ascending))
                .List<T>();
        }

        public virtual IEnumerable<T> GetAll()
        {
            return CurrentSession.CreateCriteria<T>().List<T>();
        }
    }
}